package com.spsoft.workflow.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Sets;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.model.Result;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.SecurityUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.system.constants.DefBizdictConstants;
import com.spsoft.system.entity.SysRoles;
import com.spsoft.system.model.vo.DefBizdictVo;
import com.spsoft.system.service.DefBizdictService;
import com.spsoft.workflow.common.WorkFlowConstants;
import com.spsoft.workflow.common.enums.BusFlowTypeEnums;
import com.spsoft.workflow.entity.WfProcessTemplates;
import com.spsoft.workflow.mapper.WfProcessTemplatesMapper;
import com.spsoft.workflow.model.dto.template.WfProcessTemplateSaveDto;
import com.spsoft.workflow.model.dto.template.WfProcessTemplatesQueryDto;
import com.spsoft.workflow.model.dto.json.ChildNode;
import com.spsoft.workflow.model.vo.biz.WfProcessTemplatesVo;
import com.spsoft.workflow.service.WfProcessTemplatesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spsoft.workflow.utils.BpmnModelUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 流程审批摸板;--主键序列 SEQ_WF_PROCESS_TEMPLATES 服务实现类
 * </p>
 *
 * @author dlchen
 * @since 2023-11-13
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class WfProcessTemplatesServiceImpl extends ServiceImpl<WfProcessTemplatesMapper, WfProcessTemplates> implements WfProcessTemplatesService {
    private final RepositoryService repositoryService;

    @Override
    public Result<IPage<WfProcessTemplatesVo>> queryPageList(WfProcessTemplatesQueryDto templateDto) {
        Integer pageNo = templateDto.getPageNo();
        Integer pageSize = templateDto.getPageSize();
        Page<WfProcessTemplates> page = new Page<>(pageNo, pageSize);
        LambdaQueryWrapper<WfProcessTemplates> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtil.isNotEmpty( templateDto.getTemplateName()), WfProcessTemplates::getTemplateName, templateDto.getTemplateName());
        queryWrapper.eq(StringUtil.isNotEmpty( templateDto.getBusType()), WfProcessTemplates::getBusType, templateDto.getBusType());
        queryWrapper.orderByDesc(WfProcessTemplates::getId);
        IPage templatesIPage = this.page(page, queryWrapper);
        List<WfProcessTemplates> records = templatesIPage.getRecords();
        DefBizdictService defBizdictService = SpringUtil.getBean(DefBizdictService.class);
        Result<List<DefBizdictVo>> result = defBizdictService.getDefBIzdictByLxdm(DefBizdictConstants.VMS_WORK_FLOW_TYPE);

        List<WfProcessTemplatesVo> wfProcessTemplatesVos = BeanUtils.copyListProperties(records, WfProcessTemplatesVo::new, (s, t) -> {
            if (ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
                List<DefBizdictVo> data = result.getData();
                for (DefBizdictVo defBizdictVo : data) {
                    if (s.getBusType() !=null && s.getBusType().equals(defBizdictVo.getLxxdm())) {
                        t.setBusTypeName(defBizdictVo.getLxxmc());
                    }
                }
            }
        });
        templatesIPage.setRecords(wfProcessTemplatesVos);
        return Result.OK(templatesIPage);
    }

    @Override
    public Result<WfProcessTemplates> getFormTemplateById(Long id) {
        return Result.OK(this.getById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result saveTemplate(WfProcessTemplateSaveDto templateDto) {

        LambdaQueryWrapper<WfProcessTemplates> w = new LambdaQueryWrapper<>();
        w.eq(WfProcessTemplates::getBusType, templateDto.getBusType());
        WfProcessTemplates wfProcessTemplates = this.baseMapper.selectOne(w);
        if(wfProcessTemplates != null){
            return Result.ERROR("该业务类型的流程已存在不可以重复添加");
        }

        String processJson = templateDto.getProcess();
        ChildNode childNode = JSONObject.parseObject(processJson, new TypeReference<ChildNode>() {
        });
        //流程变量
        Set<String> processVariables = Sets.newConcurrentHashSet();
        String settingsJson = templateDto.getSettings();
        String remark = templateDto.getRemark();
        String formName = templateDto.getTemplateName();
        WfProcessTemplates processTemplates = new WfProcessTemplates();
        processTemplates.setTemplateName(formName);
        processTemplates.setBusType(templateDto.getBusType());
        processTemplates.setProcess(processJson);
        processTemplates.setSettings(settingsJson);
        processTemplates.setRemark(templateDto.getRemark());
        processTemplates.setCreateBy(SecurityUtils.getUserCode());
        /**
         * 保存流程模板
         */
        this.saveOrUpdate(processTemplates);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("processJson", processJson);
        BpmnModel bpmnModel = BpmnModelUtils.assemBpmnModel(jsonObject, childNode, remark, formName,
                processTemplates.getId(), processVariables);
        processTemplates.setProcessVariables(CollUtil.join(processVariables, ","));
        this.saveOrUpdate(processTemplates);
        repositoryService.createDeployment()
                .addBpmnModel(formName + ".bpmn", bpmnModel)
                .name(formName)
                .deploy();
        return Result.OK();
    }

    @Override
    public Result updateTemplate(WfProcessTemplateSaveDto templateDto) {
        WfProcessTemplates processTemplates = this.getById(templateDto.getId());
        Set<String> processVariables = Sets.newConcurrentHashSet();
        processTemplates.setTemplateName(templateDto.getTemplateName());
        processTemplates.setSettings(templateDto.getSettings());
        processTemplates.setProcess(templateDto.getProcess());
        processTemplates.setRemark(templateDto.getRemark());
        processTemplates.setUpdateTime(new Date());
        processTemplates.setUpdateBy(SecurityUtils.getUserCode());

        ChildNode childNode = JSONObject.parseObject(templateDto.getProcess(), new TypeReference<ChildNode>() {
        });
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("processJson", templateDto.getProcess());
        BpmnModel bpmnModel = BpmnModelUtils.assemBpmnModel(jsonObject, childNode, templateDto.getRemark(),
                templateDto.getTemplateName(),  templateDto.getId(), processVariables);
        processTemplates.setProcessVariables(CollUtil.join(processVariables, ","));
        this.updateById(processTemplates);
        repositoryService.createDeployment()
                .addBpmnModel(templateDto.getTemplateName() + ".bpmn", bpmnModel)
                .name(templateDto.getTemplateName())
                .deploy();
        return Result.OK();
    }

    @Override
    public Result getBMPNXml(WfProcessTemplateSaveDto templateDto) {
        Result<Object> ok = Result.OK();
        BpmnModel bpmnModel = getBpmnModelByTemplateId(templateDto.getId());
        String bpmnXml = new String(new BpmnXMLConverter().convertToXML(bpmnModel));
        ok.setData(bpmnXml);
        return ok;
    }
    /**
     * 根据模板id获取BpmnModel
     * @param templateId
     * @return
     */
    @Override
    public BpmnModel getBpmnModelByTemplateId(Long templateId) {
        ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery().processDefinitionKey(WorkFlowConstants.PROCESS_PREFIX + templateId);
        ProcessDefinition processDefinition = definitionQuery.latestVersion().singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        return bpmnModel;
    }
    /**
     * 按业务流程类型获取表单模板
     *
     * @param busFlowTypeEnums 业务流程类型
     * @return {@link WfProcessTemplates}
     */
    @Override
    public WfProcessTemplates getFormTemplateByBusType(BusFlowTypeEnums busFlowTypeEnums){
        LambdaQueryWrapper<WfProcessTemplates> w = new LambdaQueryWrapper<>();
        w.eq(WfProcessTemplates::getBusType, busFlowTypeEnums.getCode());
        WfProcessTemplates wfProcessTemplates = this.baseMapper.selectOne(w);
        return wfProcessTemplates;
    }


}
